package com.ship.dispatch.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ship.common.business.service.impl.BaseServiceImpl;
import com.ship.common.core.constant.ShipApiConstants;
import com.ship.common.core.domain.SpPortData;
import com.ship.common.core.utils.OkHttpUtil;
import com.ship.dispatch.bean.SpPortInformation;
import com.ship.dispatch.bean.SpPortRouteDistance;
import com.ship.dispatch.model.Vo.ShipLoadDaysAndRouteVo;
import com.ship.dispatch.model.Vo.ShipRouteSearchVo;
import com.ship.dispatch.service.SpPortInformationService;
import com.ship.dispatch.service.SpPortRouteDistanceService;
import com.ship.dispatch.mapper.SpPortRouteDistanceMapper;
import com.ship.dispatch.util.CommonUtil;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
* @author 91516
* @description 针对表【sp_port_route_distance(港口航线规划距离信息)】的数据库操作Service实现
* @createDate 2024-07-10 17:44:55
*/
@Service
public class SpPortRouteDistanceServiceImpl extends BaseServiceImpl<SpPortRouteDistanceMapper, SpPortRouteDistance>
    implements SpPortRouteDistanceService{

    @Autowired
    private SpPortInformationService spPortInformationService;

    private static String shipServerHost;

    private static String shipServerAppKey;

    @Value("${ship_server.host}")
    public void setShipServerHost(String shipServerHost) {
        this.shipServerHost = shipServerHost;
    }

    @Value("${ship_server.app_key}")
    public void setShipServerAppKey(String shipServerAppKey) {
        this.shipServerAppKey = shipServerAppKey;
    }

    private static Integer[] chinaPort = new Integer[]{371,307,367};
    private static Long[] chinaPortId = new Long[]{1790602097607114754L,1790602097611309060L,1790602097619697667L};
    private static String[] chinaPortName = new String[]{"Yangpu","Tianjin","Yancheng"};
    private static Integer[] europePort = new Integer[]{1679,4092};
    private static String[] europePortName = new String[]{"Dunkirk","Sagunto"};
    private static Integer[] indiaPort = new Integer[]{2083,2081};
    private static String[] indiaPortName = new String[]{"Dhamra","Dahej"};

    @Override
    public ShipLoadDaysAndRouteVo getCommonLoadDay(List<Long> loadingSort, List<Long> unloadSort, BigDecimal speed, String passStrait, String passArea) {
        List<SpPortData> startPortList = new LinkedList<>();
        List<SpPortData> endPortList = new LinkedList<>();
        //装载港
        if (loadingSort != null && loadingSort.size() > 0) {
            for (Long aLong : loadingSort) {
                SpPortInformation portInformation = spPortInformationService.getBaseMapper().selectById(aLong);
                if (portInformation != null) {
                    SpPortData spPortData = new SpPortData();
                    spPortData.setId(portInformation.getId());
                    spPortData.setPortName(portInformation.getPortNameEnglish());
                    spPortData.setParentPortName(StringUtils.isNotBlank(portInformation.getParentPortName()) ? portInformation.getParentPortName() : portInformation.getPortNameEnglish());
                    spPortData.setThirdPortId(portInformation.getThirdPortId());
                    spPortData.setPortCountry(portInformation.getPortCountry());
                    startPortList.add(spPortData);
                }
            }
        }
        //卸载港
        if (unloadSort != null && unloadSort.size() > 0) {
            for (Long aLong : unloadSort) {
                SpPortInformation portInformation = spPortInformationService.getBaseMapper().selectById(aLong);
                if (portInformation != null) {
                    SpPortData spPortData = new SpPortData();
                    spPortData.setId(portInformation.getId());
                    spPortData.setPortName(portInformation.getPortNameEnglish());
                    spPortData.setParentPortName(StringUtils.isNotBlank(portInformation.getParentPortName()) ? portInformation.getParentPortName() : portInformation.getPortNameEnglish());
                    spPortData.setThirdPortId(portInformation.getThirdPortId());
                    spPortData.setPortCountry(portInformation.getPortCountry());
                    endPortList.add(spPortData);
                }
            }
        }

        //根据船速和装载日期生成航线、和航线对应的满载和空载航程天数
        ShipLoadDaysAndRouteVo shipLoadDaysAndRouteVo = this.getShipLoadDaysAndRouteBySpeed(speed
                , passStrait, passArea,startPortList,endPortList);
        if(shipLoadDaysAndRouteVo != null){
            shipLoadDaysAndRouteVo.setPassArea(passArea);
            shipLoadDaysAndRouteVo.setPassStrait(passStrait);
        }
        return shipLoadDaysAndRouteVo;
    }

    public ShipLoadDaysAndRouteVo getShipLoadDaysAndRouteBySpeed(BigDecimal shipSpeed
            , String passStrait, String passArea, List<SpPortData> startPortList, List<SpPortData> endPortList) {
        if(shipSpeed == null){
            shipSpeed = new BigDecimal("17");
        }
        ShipLoadDaysAndRouteVo shipLoadDaysAndRouteVo = new ShipLoadDaysAndRouteVo();

        BigDecimal shipDay = BigDecimal.ZERO;
        for (SpPortData spPortData : startPortList) {
            //航线时间
            for (SpPortData portData : endPortList) {
                ShipRouteSearchVo routeDay = getShipRouteDay(shipSpeed,spPortData.getThirdPortId()
                        ,portData.getThirdPortId(),passStrait,passArea);

                if(routeDay == null){
                    //宝船网接口获取不到数据的时候，尝试调用本地数据库维护的航线信息
                    SpPortRouteDistance distance = this.baseMapper.selectOne(
                            new LambdaQueryWrapper<SpPortRouteDistance>()
                                    .eq(SpPortRouteDistance::getStartPortName,spPortData.getParentPortName())
                                    .eq(SpPortRouteDistance::getEndPortName,portData.getParentPortName())
                                    .like(StringUtils.isNotBlank(passStrait),SpPortRouteDistance::getPassStrait,passStrait)
                                    .like(StringUtils.isNotBlank(passArea),SpPortRouteDistance::getPassArea,passArea)
                                    .isNull(StringUtils.isBlank(passStrait),SpPortRouteDistance::getPassStrait)
                                    .isNull(StringUtils.isBlank(passArea),SpPortRouteDistance::getPassArea)
                                    .last("limit 1")
                    );
                    if(distance != null && distance.getShipDistance() != null){
                        routeDay = new ShipRouteSearchVo();
                        routeDay.setTrackDistance(Integer.parseInt(distance.getShipDistance().toString()));
                        routeDay.setShipSpeed(shipSpeed);
                        routeDay.setShipRouteDay(distance.getShipDistance()
                                .divide(shipSpeed,2,RoundingMode.UP).divide(new BigDecimal("24"),0,RoundingMode.UP));

                        shipDay = routeDay.getShipRouteDay();
                        shipLoadDaysAndRouteVo.setStartPortId(spPortData.getId());
                        shipLoadDaysAndRouteVo.setStartThirdPortId(spPortData.getThirdPortId());
                        shipLoadDaysAndRouteVo.setStartPortName(spPortData.getPortName());
                        shipLoadDaysAndRouteVo.setEndPortId(portData.getId());
                        shipLoadDaysAndRouteVo.setEndThirdPortId(portData.getThirdPortId());
                        shipLoadDaysAndRouteVo.setEndPortName(portData.getPortName());
                        shipLoadDaysAndRouteVo.setShipDay(shipDay.intValue());
                        shipLoadDaysAndRouteVo.setTrackDistance(routeDay.getTrackDistance());
                    }
                }else{
                    if(routeDay.getShipRouteDay().compareTo(shipDay) > 0){
                        shipDay = routeDay.getShipRouteDay();
                        shipLoadDaysAndRouteVo.setStartPortId(spPortData.getId());
                        shipLoadDaysAndRouteVo.setStartThirdPortId(spPortData.getThirdPortId());
                        shipLoadDaysAndRouteVo.setStartPortName(spPortData.getPortName());
                        shipLoadDaysAndRouteVo.setEndPortId(portData.getId());
                        shipLoadDaysAndRouteVo.setEndThirdPortId(portData.getThirdPortId());
                        shipLoadDaysAndRouteVo.setEndPortName(portData.getPortName());
                        shipLoadDaysAndRouteVo.setShipDay(shipDay.intValue());
                        shipLoadDaysAndRouteVo.setTrackDistance(routeDay.getTrackDistance());
                    }
                }
            }
        }

        if(endPortList.size() > 0 && shipLoadDaysAndRouteVo.getShipDay() == null){
            return null;
        }

        //中国预计
        BigDecimal chinaDay = BigDecimal.ZERO;
        for (SpPortData spPortData : startPortList) {
            for (int i = 0; i < chinaPort.length; i++) {
                int portId = chinaPort[i];
                ShipRouteSearchVo routeDay = getShipRouteDay(shipSpeed,spPortData.getThirdPortId()
                        ,portId,null,null);
                if(routeDay == null){
                    //宝船网接口获取不到数据的时候，尝试调用本地数据库维护的航线信息
                    SpPortRouteDistance distance = this.baseMapper.selectOne(
                            new LambdaQueryWrapper<SpPortRouteDistance>()
                                    .eq(SpPortRouteDistance::getStartPortName,spPortData.getParentPortName())
                                    .eq(SpPortRouteDistance::getEndPortName,chinaPortName[i])
                                    .isNull(SpPortRouteDistance::getPassStrait)
                                    .isNull(SpPortRouteDistance::getPassArea)
                                    .last("limit 1")
                    );
                    if(distance != null && distance.getShipDistance() != null) {
                        routeDay = new ShipRouteSearchVo();
                        routeDay.setTrackDistance(Integer.parseInt(distance.getShipDistance().toString()));
                        routeDay.setShipSpeed(shipSpeed);
                        routeDay.setShipRouteDay(distance.getShipDistance()
                                .divide(shipSpeed, 2, RoundingMode.UP).divide(new BigDecimal("24"), 0, RoundingMode.UP));
                    }
                }

                if(routeDay != null && routeDay.getShipRouteDay().compareTo(chinaDay) > 0){
                    chinaDay = routeDay.getShipRouteDay();
                    shipLoadDaysAndRouteVo.setChinaDays(chinaDay.intValue());
                    if(endPortList.size() == 0){
                        //如果没有选择卸载港，则默认回国，卸载港为中国最远港口
                        shipLoadDaysAndRouteVo.setStartPortId(spPortData.getId());
                        shipLoadDaysAndRouteVo.setStartThirdPortId(spPortData.getThirdPortId());
                        shipLoadDaysAndRouteVo.setStartPortName(spPortData.getPortName());
                        shipLoadDaysAndRouteVo.setEndPortId(chinaPortId[i]);
                        shipLoadDaysAndRouteVo.setEndThirdPortId(portId);
                        shipLoadDaysAndRouteVo.setEndPortName(chinaPortName[i]);
                        shipLoadDaysAndRouteVo.setShipDay(chinaDay.intValue());
                        shipLoadDaysAndRouteVo.setTrackDistance(routeDay.getTrackDistance());
                    }
                }
            }
        }

        //欧洲预计
        BigDecimal europeDay = BigDecimal.ZERO;
        for (SpPortData spPortData : startPortList) {
            for (int i = 0; i < europePort.length; i++) {
                int portId = europePort[i];
                ShipRouteSearchVo routeDay = getShipRouteDay(shipSpeed,spPortData.getThirdPortId()
                        ,portId,null,null);
                if(routeDay == null){
                    //宝船网接口获取不到数据的时候，尝试调用本地数据库维护的航线信息
                    SpPortRouteDistance distance = this.baseMapper.selectOne(
                            new LambdaQueryWrapper<SpPortRouteDistance>()
                                    .eq(SpPortRouteDistance::getStartPortName,spPortData.getParentPortName())
                                    .eq(SpPortRouteDistance::getEndPortName,europePortName[i])
                                    .isNull(SpPortRouteDistance::getPassStrait)
                                    .isNull(SpPortRouteDistance::getPassArea)
                                    .last("limit 1")
                    );
                    if(distance != null && distance.getShipDistance() != null) {
                        routeDay = new ShipRouteSearchVo();
                        routeDay.setTrackDistance(Integer.parseInt(distance.getShipDistance().toString()));
                        routeDay.setShipSpeed(shipSpeed);
                        routeDay.setShipRouteDay(distance.getShipDistance()
                                .divide(shipSpeed, 2, RoundingMode.UP).divide(new BigDecimal("24"), 0, RoundingMode.UP));
                    }
                }
                if(routeDay != null && routeDay.getShipRouteDay().compareTo(europeDay) > 0){
                    europeDay = routeDay.getShipRouteDay();
                    shipLoadDaysAndRouteVo.setEuropeDays(europeDay.intValue());
                }
            }
        }

        //印度预计
        BigDecimal indiaDay = BigDecimal.ZERO;
        for (SpPortData spPortData : startPortList) {
            for (int i = 0; i < indiaPort.length; i++) {
                int portId = indiaPort[i];
                ShipRouteSearchVo routeDay = getShipRouteDay(shipSpeed,spPortData.getThirdPortId()
                        ,portId,null,null);
                if(routeDay == null){
                    //宝船网接口获取不到数据的时候，尝试调用本地数据库维护的航线信息
                    SpPortRouteDistance distance = this.baseMapper.selectOne(
                            new LambdaQueryWrapper<SpPortRouteDistance>()
                                    .eq(SpPortRouteDistance::getStartPortName,spPortData.getParentPortName())
                                    .eq(SpPortRouteDistance::getEndPortName,indiaPortName[i])
                                    .isNull(SpPortRouteDistance::getPassStrait)
                                    .isNull(SpPortRouteDistance::getPassArea)
                                    .last("limit 1")
                    );
                    if(distance != null && distance.getShipDistance() != null) {
                        routeDay = new ShipRouteSearchVo();
                        routeDay.setTrackDistance(Integer.parseInt(distance.getShipDistance().toString()));
                        routeDay.setShipSpeed(shipSpeed);
                        routeDay.setShipRouteDay(distance.getShipDistance()
                                .divide(shipSpeed, 2, RoundingMode.UP).divide(new BigDecimal("24"), 0, RoundingMode.UP));
                    }
                }
                if(routeDay != null && routeDay.getShipRouteDay().compareTo(indiaDay) > 0){
                    indiaDay = routeDay.getShipRouteDay();
                    shipLoadDaysAndRouteVo.setIndiaDays(indiaDay.intValue());
                }
            }
        }
        return shipLoadDaysAndRouteVo;
    }

    /**
     * 根据装卸载港计算航行天数
     * @param shipSpeed
     * @param passStrait
     * @param passArea
     * @return
     */
    @Override
    public ShipRouteSearchVo getShipRouteDay(BigDecimal shipSpeed,Integer startPortId
            ,Integer endPortId, String passStrait, String passArea){
        if(startPortId == null || endPortId == null){
            return null;
        }
        JSONObject paramJson = new JSONObject();
        paramJson.put("startPortId",startPortId);
        paramJson.put("endPortId",endPortId);
        if(StringUtils.isNotBlank(passStrait)){
            paramJson.put("passStrait",passStrait);
        }
        if(StringUtils.isNotBlank(passArea)){
            paramJson.put("passArea",passArea);
        }
        RequestBody body = RequestBody.create(paramJson.toJSONString(), MediaType.parse("application/json"));
        Map<String, String> headers = new HashedMap<>();
        headers.put("AppKey",shipServerAppKey);
        Object resultObj = OkHttpUtil.sendOkHttpClient(shipServerHost+ ShipApiConstants.EXAPI_SHIPROUTE_QUERY
                , "POST",body,headers);
        System.out.println(shipServerHost+"航线规划结果=============="+resultObj);
        if(resultObj == null){
            return null;
        }
        JSONObject resultJson = JSONObject.parseObject(String.valueOf(resultObj));
        String sailDistance = "";
        if(!StringUtils.equals("0",resultJson.getString("code"))){
            return null;
        }else{
            JSONArray jsonArray = resultJson.getJSONArray("data");
            if(jsonArray.size() == 0){
                return null;
            }
            JSONObject distanceJson = JSONObject.parseObject(jsonArray.get(0).toString());
            sailDistance = distanceJson.getString("trackDistance");
        }

        ShipRouteSearchVo routeSearchVo = new ShipRouteSearchVo();
        routeSearchVo.setTrackDistance(Integer.parseInt(sailDistance));
        routeSearchVo.setShipSpeed(shipSpeed);
        routeSearchVo.setShipRouteDay(new BigDecimal(sailDistance)
                .divide(shipSpeed,2,RoundingMode.UP).divide(new BigDecimal("24"),0,RoundingMode.UP));
        return routeSearchVo;
    }

    @Override
    public ShipRouteSearchVo getShipRouteDayByThirdId(BigDecimal shipSpeed, Integer expectedUnloadThirdId, Integer expectedLoadThirdId, String passStrait, String passArea) {
        ShipRouteSearchVo searchVo = this.getShipRouteDay(shipSpeed,expectedUnloadThirdId,expectedLoadThirdId,passStrait,passArea);
        if(searchVo != null){
            return searchVo;
        }
        //根据第三方ID反查港口信息
        String startPortName = "";
        String endPortName = "";
        SpPortInformation startPort = spPortInformationService.getBaseMapper().selectOne(
                new LambdaQueryWrapper<SpPortInformation>()
                        .eq(SpPortInformation::getThirdPortId,expectedUnloadThirdId)
                        .eq(SpPortInformation::getPortType,1)
                        .last("limit 1")
        );
        if(startPort != null){
            startPortName = startPort.getPortNameEnglish();
        }
        SpPortInformation endPort = spPortInformationService.getBaseMapper().selectOne(
                new LambdaQueryWrapper<SpPortInformation>()
                        .eq(SpPortInformation::getThirdPortId,expectedLoadThirdId)
                        .eq(SpPortInformation::getPortType,1)
                        .last("limit 1")
        );
        if(endPort != null){
            endPortName = endPort.getPortNameEnglish();
        }
        if(StringUtils.isBlank(startPortName) || StringUtils.isBlank(endPortName)){
            return null;
        }

        SpPortRouteDistance distance = this.baseMapper.selectOne(
                new LambdaQueryWrapper<SpPortRouteDistance>()
                        .eq(SpPortRouteDistance::getStartPortName,startPortName)
                        .eq(SpPortRouteDistance::getEndPortName,endPortName)
                        .like(StringUtils.isNotBlank(passStrait),SpPortRouteDistance::getPassStrait,passStrait)
                        .like(StringUtils.isNotBlank(passArea),SpPortRouteDistance::getPassArea,passArea)
                        .isNull(StringUtils.isBlank(passStrait),SpPortRouteDistance::getPassStrait)
                        .isNull(StringUtils.isBlank(passArea),SpPortRouteDistance::getPassArea)
                        .last("limit 1")
        );
        if(distance != null && distance.getShipDistance() != null){
            searchVo = new ShipRouteSearchVo();
            searchVo.setTrackDistance(Integer.parseInt(distance.getShipDistance().toString()));
            searchVo.setShipSpeed(shipSpeed);
            searchVo.setShipRouteDay(distance.getShipDistance()
                    .divide(shipSpeed,2,RoundingMode.UP).divide(new BigDecimal("24"),0,RoundingMode.UP));
            return searchVo;
        }
        return null;
    }

    @Override
    public void portRouteRelationUpdate() {
        List<SpPortInformation> portInformations = spPortInformationService.getBaseMapper().selectList(
                new LambdaUpdateWrapper<SpPortInformation>()
                .isNull(SpPortInformation::getThirdPortId)
        );
        for (SpPortInformation portInformation : portInformations) {
            String thirdId = CommonUtil.getPortThirdId(portInformation);
            if(StringUtils.isNotBlank(thirdId)){
                portInformation.setThirdPortId(Integer.parseInt(thirdId));
            }
            spPortInformationService.getBaseMapper().updateById(portInformation);
        }
    }

}




